package de.slothsoft.commons.reflection;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import de.slothsoft.commons.debug.Console;

public class JarUtil {

	private final static String CLASS_EXTENSION = ".class";

	/**
	 * Find all the classes of a jar file. (Do not use for big jars!)
	 * 
	 * @param jarFile
	 * @throws IOException
	 */

	public static List<Class<?>> find(File jarFile) throws IOException {

		JarFile jar = new JarFile(jarFile);

		List<String> clazzNames = findClassNames(jar);
		return getClazzes(jarFile.toURI().toURL(), clazzNames);
	}

	/*
	 * 
	 */

	private static List<String> findClassNames(JarFile jar) {
		List<String> clazzNames = new ArrayList<String>();

		int size = jar.size();
		Enumeration<JarEntry> jarEntries = jar.entries();
		for (int i = 0; i < size; i++) {
			JarEntry jarEntry = jarEntries.nextElement();
			String clazzName = jarEntry.getName();
			if (clazzName.toLowerCase().endsWith(CLASS_EXTENSION)) {
				clazzNames.add(extractClassName(clazzName));
			}
		}
		return clazzNames;
	}

	/*
	 * 
	 */

	private static String extractClassName(String clazzName) {
		return clazzName.substring(0, clazzName.lastIndexOf('.')).replace("/", ".");
	}

	/*
	 * 
	 */

	private static List<Class<?>> getClazzes(URL url, List<String> clazzNames) {
		List<Class<?>> clazzes = new ArrayList<Class<?>>();

		URLClassLoader classLoader = new URLClassLoader(new URL[] { url });

		for (String clazzName : clazzNames) {
			try {
				clazzes.add(Class.forName(clazzName, false, classLoader));
			} catch (ClassNotFoundException e) {
				// should not happen at all
				Console.error(clazzName + " was not found!!!");
			}
		}
		return clazzes;
	}
}
